﻿module Sustainalytics.News {

    import Common = Sustainalytics.Common;
    import Pager = Sustainalytics.Pager;

    // News List controller
    export class NewsListController {

        // specifies whether current controller is in loading state
        public isLoading: boolean;

        // controller scope
        public $scope: ng.IScope;

        // services
        private $q: ng.IQService;
        private $location: ng.ILocationService;
        private newsAvailabilityService: NewsAvailabilityService;
        private newsCategoryService: NewsCategoryService;
        private newsRegionService: NewsRegionService;
        private newsService: NewsService;
        private newsStatusService: NewsStatusService;
        private notificationFactory: INotificationFactory;

        // paged list of news
        public newsPaged: Common.PagedList<NewsDto>;
        // news filter
        public newsFilter: NewsFilter;
        // news temp filter - used by UI and when search button is pressed set newsFilter based on newsFilterTemp
        public newsFilterTemp: NewsFilter;
        // whether all items are selected
        public selectAll: boolean;
        // order by column
        public orderByCol: string;
        // order by direction
        public orderByColAsc: boolean;

        // news availabilities
        public newsAvailabilitiesDic: any;
        public newsAvailabilities: NewsAvailability[];
        // news categories
        public newsCategoriesDic: any;
        public newsCategories: NewsCategory[];
        // news regions
        public newsRegionsDic: any;
        public newsRegions: NewsRegion[];
        // news statuses
        public newsStatusesDic: any;
        public newsStatuses: NewsStatus[];


        // Ctor.
        constructor($scope: ng.IScope, $q: ng.IQService, $location: ng.ILocationService, NewsAvailabilityService, NewsCategoryService, NewsRegionService, NewsService, NewsStatusService, notificationFactory: INotificationFactory) {
            var ctx = this;

            $scope['newsList'] = ctx;

            ctx.$scope = $scope;
            ctx.$q = $q;
            ctx.$location = $location;
            ctx.newsAvailabilityService = NewsAvailabilityService;
            ctx.newsCategoryService = NewsCategoryService;
            ctx.newsRegionService = NewsRegionService;
            ctx.newsService = NewsService;
            ctx.newsStatusService = NewsStatusService;
            ctx.notificationFactory = notificationFactory;

            ctx.newsFilter = new NewsFilter();
            ctx.newsFilterTemp = new NewsFilter();
            ctx.orderByCol = 'DateCreated';
            ctx.orderByColAsc = false;

            // load all required data
            var loadPromise: ng.IPromise<{}> = ctx.load();

            // handle pager changed event
            ctx.$scope.$on('pagerChanged', function (event, pager) {
                ctx.getNews();
            });

            // notify parents that the controller was created
            $scope.$emit('newsList.created', ctx);

            ctx.handleSelectAll();
            ctx.handleNewsFilterTermChanged();
        }

        // load all required info
        private load(): ng.IPromise<{}> {
            var ctx = this;

            ctx.isLoading = true;

            // populate news availabilities
            var newsAvailabilitiesPromise = ctx.populateNewsAvailabilities();
            // populate news categories
            var newsCategoriesPromise = ctx.populateNewsCategories();
            // populate news regions
            var newsRegionsPromise = ctx.populateNewsRegions();
            // populate news statuses
            var newsStatusesPromise = ctx.populateNewsStatuses();

            // create a promise based on all promises
            var allPromise = ctx.$q.all([newsAvailabilitiesPromise, newsCategoriesPromise, newsRegionsPromise, newsRegionsPromise, newsStatusesPromise ]);

            allPromise.finally(function () {
                ctx.isLoading = false;
            });

            return allPromise;
        }


        // populate all news availabilities
        private populateNewsAvailabilities(): ng.IPromise<NewsAvailability[]> {
            var ctx = this;

            var getPromise: ng.IPromise<NewsAvailability[]> = ctx.newsAvailabilityService.getNewsAvailabilities();

            getPromise.then(function (newsAvailabilities: NewsAvailability[]) {
                ctx.newsAvailabilitiesDic = {};
                ctx.newsAvailabilities = newsAvailabilities;
                $(newsAvailabilities).each(function () { ctx.newsAvailabilitiesDic[this.id] = this; });
            });

            return getPromise;
        }

        // populate all news categories
        private populateNewsCategories(): ng.IPromise<NewsCategory[]> {
            var ctx = this;

            var getPromise: ng.IPromise<NewsCategory[]> = ctx.newsCategoryService.getNewsCategories();

            getPromise.then(function (newsCategories: NewsCategory[]) {
                ctx.newsCategoriesDic = {};
                ctx.newsCategories = newsCategories;
                $(newsCategories).each(function () { ctx.newsCategoriesDic[this.id] = this; });
            });

            return getPromise;
        }

        // populate all news regions
        private populateNewsRegions(): ng.IPromise<NewsRegion[]> {
            var ctx = this;

            var getPromise: ng.IPromise<NewsRegion[]> = ctx.newsRegionService.getNewsRegions();

            getPromise.then(function (newsRegions: NewsRegion[]) {
                ctx.newsRegionsDic = {};
                ctx.newsRegions = newsRegions;
                $(newsRegions).each(function () { ctx.newsRegionsDic[this.id] = this; });
            });

            return getPromise;
        }

        // populate all news statuses
        private populateNewsStatuses(): ng.IPromise<NewsStatus[]> {
            var ctx = this;

            var getPromise: ng.IPromise<NewsStatus[]> = ctx.newsStatusService.getNewsStatuses();

            getPromise.then(function (newsStatuses: NewsStatus[]) {
                ctx.newsStatusesDic = {};
                ctx.newsStatuses = newsStatuses;
                $(newsStatuses).each(function () { ctx.newsStatusesDic[this.id] = this; });
            });

            return getPromise;
        }

        // get list of news - paged and filtered
        public getNews(pageIndex?: number, pageSize?: number) {

            var ctx = this;

            ctx.isLoading = true;

            // get current pager
            var pager: Pager.PagerController = ctx.$scope['pager'];

            if (!pager)
                return;

            if (pageIndex != null)
                pager.pagingOptions.pageIndex = pageIndex;

            if (pageSize != null)
                pager.pagingOptions.pageSize = pageSize;

            // create order by criteria
            var orderBy = ctx.orderByCol && ctx.orderByCol !== '' ? (ctx.orderByCol + (ctx.orderByColAsc ? ' ASC' : ' DESC')) : null;

            // get news items
            var newsPagedPromise: ng.IPromise<Common.PagedList<NewsDto>> = ctx.newsService.getNewsPaged(ctx.newsFilter, pager.skipCount(), pager.takeCount(), [ctx.orderByCol], ctx.orderByColAsc);

            // on success set list of news
            newsPagedPromise.then(function (newsPaged) {
                var currentPage = pager.pagingOptions.pageIndex;
                ctx.newsPaged = newsPaged;
                pager.loadPagingFromPagedList(ctx.newsPaged);

                // if current page is empty but there are items then go to previous page
                if (ctx.newsPaged.totalItemsCount > 0 && ctx.newsPaged.items.length == 0 && ctx.newsPaged.pagingOptions.pageIndex > 1) {
                    var prevPage = Math.min(ctx.newsPaged.totalPageCount, currentPage - 1);
                    ctx.getNews(prevPage);
                }
            });

            newsPagedPromise.finally(function () {
                ctx.isLoading = false;
            });
        }

        // execute search and apply filter
        public search() {
            var ctx = this;

            if (ctx.newsFilterTemp.term !== '' && ctx.newsFilterTemp.term && ctx.newsFilterTemp.term.length < 3) {
                ctx.notificationFactory.error('', 'Please enter a search criteria of more than 3 characters');
                return;
            }

            // set filter
            //$.extend(true, ctx.newsFilter, ctx.newsFilterTemp);

            ctx.newsFilter.term = ctx.newsFilterTemp.term;

            // execute get
            ctx.getNews(1);
        }

        // delete selected news
        public deleteNews(): ng.IPromise<Object> {
            var ctx = this;            

            if (ctx.newsPaged && ctx.newsPaged.items && ctx.newsPaged.items.length > 0) {

                // get selected news
                var newsItems: string[] = $(ctx.getSelectedItems()).map(function () { return this.id; }).get();

                if (newsItems.length == 0) {
                    ctx.notificationFactory.error('', 'Please make a selection and try again.');
                }

                if (newsItems.length > 0) {
                    if (confirm('Are you sure you want to delete this\these article(s)?') == false) {
                        var def = ctx.$q.defer();
                        def.resolve();
                        return def.promise;
                    }

                    ctx.isLoading = true;

                    var patchNews: NewsPatch = new NewsPatch();
                    patchNews.deleteItems = newsItems;

                    // delete selected news
                    var delPromise: ng.IPromise<{}> = ctx.newsService.patchNews(patchNews);

                    delPromise.then(function () {
                        ctx.notificationFactory.success('The items were deleted.');
                    });

                    delPromise.finally(function () {
                        ctx.isLoading = false;

                        // repopulate list
                        ctx.getNews();
                    });

                    return delPromise;
                }
            }
            
            var def = ctx.$q.defer();
            def.resolve();
            return def.promise;
        }

        // publish multiple news
        public publishMultipleNews(): ng.IPromise<Object> {

            var ctx = this;

            if (ctx.newsPaged && ctx.newsPaged.items && ctx.newsPaged.items.length > 0) {

                // get selected news
                var newsItems: string[] = $(ctx.getSelectedItems()).map(function () { return this.id; }).get();

                if (newsItems.length > 0) {
                    if (confirm(newsItems.length + ' items will be published.') == false) {
                        var def = ctx.$q.defer();
                        def.resolve();
                        return def.promise;
                    }

                    ctx.isLoading = true;

                    var patchNews: NewsPatch = new NewsPatch();
                    patchNews.publishNewsItems = newsItems;

                    // delete selected news
                    var pubPromise: ng.IPromise<{}> = ctx.newsService.patchNews(patchNews);

                    pubPromise.then(function () {
                        ctx.notificationFactory.success('The items were published.');
                    });

                    pubPromise.finally(function () {
                        ctx.isLoading = false;

                        // refresh news
                        ctx.getNews();
                    });

                    return pubPromise;
                }
            }

            var def = ctx.$q.defer();
            def.resolve();
            return def.promise;
        }

        // get selected items
        public getSelectedItems(): NewsDto[] {
            var ctx = this;

            if (ctx.newsPaged && ctx.newsPaged.items && ctx.newsPaged.items.length > 0) {
                var items = $(ctx.newsPaged.items).filter(function () { return this.selected; }).get();
                return items;
            }

            return new Array();
        }

        // switch to add news mode
        public addNews() {
            this.$location.path('/news/add');
        }

        // switch to edit news mode
        public editNews(newsId: string) {
            this.$location.path('/news/edit/' + newsId);
        }

        // select all
        private handleSelectAll() {
            var ctx = this;

            ctx.$scope.$watch('newsList.selectAll', function () {
                if (ctx.newsPaged && ctx.newsPaged.items && ctx.newsPaged.items.length > 0) {
                    {
                        $(ctx.newsPaged.items).each(function () { this.selected = ctx.selectAll; });
                    }
                }
            });
        }

        // news filter term changed
        private handleNewsFilterTermChanged() {
            var ctx = this;
            this.$scope.$watch('newsList.newsFilter.category', function () {
                ctx.getNews(1);
            });
        }

        // when orderBy changes execute a get()
        public changeOrderBy(col) {
            var ctx = this;
            var oldCol = ctx.orderByCol;

            if (oldCol === col) {
                ctx.orderByColAsc = !ctx.orderByColAsc;
            }
            else {
                ctx.orderByCol = col;
                ctx.orderByColAsc = true;
            }

            ctx.getNews();
        }
    }

    // register controller with News Angular module
    angular.module('Sustainalytics.News').controller('NewsListController', function ($scope: ng.IScope, $q: ng.IQService, $location: ng.ILocationService, NewsAvailabilityService, NewsCategoryService, NewsRegionService, NewsService, NewsStatusService, notificationFactory: INotificationFactory) {
        var ctrl = new NewsListController($scope, $q, $location, NewsAvailabilityService, NewsCategoryService, NewsRegionService, NewsService, NewsStatusService, notificationFactory);
        return ctrl;
    });
}